package com.yuandian.management.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.constant.RedisKey;
import com.yuandian.management.mapper.ConfExclusiveIndicatorMapper;
import com.yuandian.management.service.*;
import com.yuandian.management.utils.RedisUtil;
import com.yuandian.management.vo.ExclusiveIndicatorVo;
import com.yuandian.management.vo.IndicatorSyncResourceVo;
import com.yuandian.management.vo.IndicatorsSyncParams;
import com.yuandian.utils.BeanUtils;
import com.yuandian.utils.PageDataInfo;
import com.yuandian.utils.YDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 专属指标查询
 */
@Service
@Slf4j
public class ExclusiveIndicatorServiceImpl extends ServiceImpl<ConfExclusiveIndicatorMapper, ConfExclusiveIndicator>
		implements ExclusiveIndicatorService {

	@Autowired
	ConfResourceService confResourceService;
	@Autowired
	ConfStepService confStepService;
	@Autowired
	ConfBusinessService businessService;
	@Autowired
	ConfExclusiveIndicatorMapper confExclusiveIndicatorMapper;
	@Autowired
	RedisUtil redisUtil;

	@Autowired
	ConfSegmentService confSegmentService;
	@Autowired
	ConfExclusiveIndicatorService confExclusiveIndicatorService;

	@PostConstruct
	public void initConfig() {
		log.info("load ExclusiveIndicator start...");
		//加载专属指标到缓存中
		loadConfig(true);
	}


	public void loadConfig(boolean needRefresh) {
		getResourcesIndicatorsShowMap(needRefresh);
		getBusinessIndicatorsShowMap(needRefresh);
		querySegmentConnectList(needRefresh);
	}


	/**
	 * 获取服务资源和专属指标map
	 *
	 * @return Map<resourceCode, Lis < 专属指标>>
	 */
	@Override
	public Map<String, List<String>> getResourcesIndicatorsShowMap(boolean needRefresh) {
		Map<String, List<String>> map = new HashMap<>();
		if(!needRefresh){
			map = redisUtil.getCacheMap(RedisKey.MANAGEMENT_RESOURCE_INDICATOR_MAP);
		}
		if(ObjectUtil.isEmpty(map)){
			map = new HashMap<>();
			ConfExclusiveIndicator confExclusiveIndicator = new ConfExclusiveIndicator();
			confExclusiveIndicator.setPageNum(-1);
			confExclusiveIndicator.setIsShow(1);//只查显示的指标
			//1、获取所有专属指标
			List<ExclusiveIndicatorVo> exclusiveIndicatorVos = confExclusiveIndicatorService.listPage(confExclusiveIndicator).getRecords();
			if (ObjectUtil.isNotEmpty(exclusiveIndicatorVos)) {
				//根据resourceCode分组
				map = exclusiveIndicatorVos.stream().collect(Collectors.toMap(ExclusiveIndicatorVo::getResourceCode, each -> Collections.singletonList(each.getName()), (value1, value2) -> {
					List<String> union = new ArrayList<>(value1);
					union.addAll(value2);
					return union;
				}));
			}
			redisUtil.setCacheMap(RedisKey.MANAGEMENT_RESOURCE_INDICATOR_MAP, map);
		}
		return map;
	}

	/**
	 * 获取业务和专属指标map 业务对应的专属指标，list为要显示的指标
	 *
	 * @return
	 */
	@Override
	public Map<String, List<String>> getBusinessIndicatorsShowMap(boolean needRefresh) {
		Map<String, List<String>> map = new HashMap<>();
		if (!needRefresh) {
			map = redisUtil.getCacheMap(RedisKey.MANAGEMENT_BUSINESS_INDICATOR_MAP);
		}
		//1、获取所有业务
		if(ObjectUtil.isEmpty(map)){
			List<ConfBusiness> businesses = businessService.list();
			if (ObjectUtil.isNotEmpty(businesses)) {
				//2、找出业务下的所有步骤并整理成map
				List<String> businessCodes = businesses.stream().map(ConfBusiness::getBusinessCode).collect(Collectors.toList());
				ConfStep confStep = new ConfStep();
				confStep.setBusinessCodes(businessCodes);
				List<ConfStep> stepByBusinessCodes = confStepService.getStepByBusinessCodes(confStep);
				//整理证map<businessCode, List<stepCode>>
				Map<String, List<String>> busCodeStep = stepByBusinessCodes.stream().collect(Collectors.toMap(ConfStep::getBusinessCode, each -> Collections.singletonList(each.getStepCode()), (value1, value2) -> {
					List<String> union = new ArrayList<>(value1);
					union.addAll(value2);
					return union;
				}));
				//3、获取以业务服务资源，专属指标map
				Map<String, List<String>> resourcesIndicatorsShowMap = getResourcesIndicatorsShowMap(false);
				for (ConfBusiness business : businesses) {
					String businessCode = business.getBusinessCode();
					List<String> list = map.get(businessCode);
					if (ObjectUtil.isEmpty(list)) {
						list = new ArrayList<>();
					}
					//该业务下的所有步骤编码
					List<String> stepCodes = busCodeStep.get(businessCode);
					if (ObjectUtil.isNotEmpty(stepCodes)) {
						for (String stepCode : stepCodes) {
							List<String> resourcesIndicators = resourcesIndicatorsShowMap.get(stepCode);
							if (ObjectUtil.isNotEmpty(resourcesIndicators)) {
								list.addAll(resourcesIndicators);
							}
						}
					}
				}
			}
			//把新的查询重新写入redis
			redisUtil.setCacheMap(RedisKey.MANAGEMENT_BUSINESS_INDICATOR_MAP, map);
		}
		return map;
	}

	/**
	 * 端到端关联专属指标
	 *
	 * @return
	 */
	@Override
	public Map<String, HashMap<String, Integer>> querySegmentConnectList(boolean needRefresh) {
		// 端到端关联专属指标Map
		Map<String, HashMap<String, Integer>> segmentConnectExcIndicatorsMap = new HashMap<>();
		try {
			String redisKey = RedisKey.SEGMENT_CONNECT_EXCINDICATORS_MAP;
			if (!needRefresh) {
				segmentConnectExcIndicatorsMap = redisUtil.getCacheMap(redisKey);
			}
			// 如果从缓存里面查询出来的值为空或者size为0，再从数据库查一次
			if (ObjectUtil.isEmpty(segmentConnectExcIndicatorsMap)) {
				ConfExclusiveIndicator confExclusiveIndicator = new ConfExclusiveIndicator();
				confExclusiveIndicator.setRelevanceType(1);
				confExclusiveIndicator.setPageNum(-1);
				List<ExclusiveIndicatorVo> records = confExclusiveIndicatorService.listPage(confExclusiveIndicator).getRecords();
				for (ExclusiveIndicatorVo exclusiveIndicator : records) {
					String name = exclusiveIndicator.getName();
					//服务资源编码
					String res = exclusiveIndicator.getResourceCode();
					//关联类型
					Integer relevanceType = exclusiveIndicator.getRelevanceType();
					if (segmentConnectExcIndicatorsMap.get(res) == null) {
						HashMap<String, Integer> exiMap = new HashMap<>();
						exiMap.put(name, relevanceType);
						segmentConnectExcIndicatorsMap.put(res, exiMap);
					} else {
						segmentConnectExcIndicatorsMap.get(res).put(name, relevanceType);
					}
				} // end for

				// 把新的查询重新写入redis
				redisUtil.setCacheMap(redisKey, segmentConnectExcIndicatorsMap);

			} // end if
		} catch (Exception e) {
			log.error("端到端关联专属指标获取异常!", e);
		}
		return segmentConnectExcIndicatorsMap;
	}



	/**
	 * 批量修改
	 *
	 * @param confExclusiveIndicator
	 * @return
	 */
	@Override
	public R<String> batchEdit(ConfExclusiveIndicator confExclusiveIndicator) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("isShow", confExclusiveIndicator.getIsShow());
		jsonObject.put("isDeal", confExclusiveIndicator.getIsDeal());
		jsonObject.put("isUserFlag", confExclusiveIndicator.getIsUserFlag());
		jsonObject.put("isChannel", confExclusiveIndicator.getIsChannel());
		jsonObject.put("isRegion", confExclusiveIndicator.getIsRegion());
		jsonObject.put("isCustomReqCode", confExclusiveIndicator.getIsCustomReqCode());
		jsonObject.put("isBusinessHallCode", confExclusiveIndicator.getIsBusinessHallCode());
		jsonObject.put("isOperatorCode", confExclusiveIndicator.getIsOperatorCode());
		jsonObject.put("isPhoneNumber", confExclusiveIndicator.getIsPhoneNumber());
		jsonObject.put("isAlarm", confExclusiveIndicator.getIsAlarm());
		jsonObject.put("isBackFill", confExclusiveIndicator.getIsBackFill());
		jsonObject.put("relevanceType", confExclusiveIndicator.getRelevanceType());
		jsonObject.put("isShowSensitive", confExclusiveIndicator.getIsShowSensitive());
		jsonObject.put("decodeType", confExclusiveIndicator.getDecodeType());
		jsonObject.put("isRetainOri",confExclusiveIndicator.getIsRetainOri());
		jsonObject.put("isFullExtraction", confExclusiveIndicator.getIsFullExtraction());
		jsonObject.put("isExportSensitive", confExclusiveIndicator.getIsExportSensitive());
		jsonObject.put("sensitiveStartValue", confExclusiveIndicator.getSensitiveStartValue());
		jsonObject.put("sensitiveLength", confExclusiveIndicator.getSensitiveLength());
		LambdaUpdateWrapper<ConfExclusiveIndicator> exclusiveIndicatorLambdaUpdateWrapper = Wrappers.lambdaUpdate();
		exclusiveIndicatorLambdaUpdateWrapper.set(ConfExclusiveIndicator::getDetail, jsonObject.toString());
		exclusiveIndicatorLambdaUpdateWrapper.in(ConfExclusiveIndicator::getId, confExclusiveIndicator.getIds());
		super.update(exclusiveIndicatorLambdaUpdateWrapper);
		return R.ok();
	}

	@Override
	public R<PageDataInfo> querySureOrAlreadySyncResource(IndicatorsSyncParams params) {
		switch (params.getSyncType()) {
			case CHILD:
				// 同步子资源
				return queryChildSyncResource(params);
			case SEGMENT:
				// 同步同一网端资源
				return querySegmentSyncResource(params);
			case BUSINESS:
				// 同步同一业务资源
				return queryBusinessSyncResource(params);
			case PARENT:
				// 同步父资源
				return queryParentSyncResource(params);
			default:
				return R.failed();
		}
	}

	/**
	 * 查询类型为子资源的可同步或已同步的业务服务资源列表
	 * @param params 专属指标同步请求参数
	 * @return 通用分页对象
	 */
	private R<PageDataInfo> queryChildSyncResource(IndicatorsSyncParams params) {


		Page<IndicatorSyncResourceVo> page = null;
		if (params.getPageNum() > 0 && params.getPageSize() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}


		List<IndicatorSyncResourceVo> list = confExclusiveIndicatorMapper.queryChildSyncResource(page, params);

		if (page == null) {
			return R.ok(new PageDataInfo(list.size(), list));
		}

		return R.ok(new PageDataInfo(page, list));
	}

	/**
	 * 查询类型为同一网端的可同步或已同步的业务服务资源列表
	 * @param params 专属指标同步请求参数
	 * @return 通用分页对象
	 */
	private R<PageDataInfo> querySegmentSyncResource(IndicatorsSyncParams params) {
		List<IndicatorSyncResourceVo> list;
		Page<IndicatorSyncResourceVo> page = null;
		if (params.getPageNum() > 0 && params.getPageSize() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}

		// 1、判断网端id是否为空，说明该专属指标没有关联网端
		if (params.getSegmentId() == null) {
			return R.ok();
		}
		// 2、根据网端id查询网端
		ConfSegment segment = confSegmentService.getById(params.getSegmentId());

		// 3、如果是首端，查询所有步骤的可同步资源列表
		if (segment.getSign() == 1) {
			list = confExclusiveIndicatorMapper.queryHeadSegmentSyncResource(params, page);
			if (page == null) {
				return R.ok(new PageDataInfo(list.size(), list));
			}
			return R.ok(new PageDataInfo(page, list));
		}

		// 4、根据网端id查询端到端关联表，非首端的可同步或已同步的业务服务资源列表
		list = confExclusiveIndicatorMapper.querySegmentSyncResource(page, params);

		if (page == null) {
			return  R.ok(new PageDataInfo(list.size(), list));
		}

		return R.ok();
	}


	/**
	 * 查询类型为同一业务的可同步或已同步的业务服务资源列表
	 * @param params 专属指标同步请求参数
	 * @return 通用分页对象
	 */
	private R<PageDataInfo> queryBusinessSyncResource(IndicatorsSyncParams params) {
		Page<IndicatorSyncResourceVo> page = null;
		if (params.getPageNum() > 0 && params.getPageSize() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}


		List<IndicatorSyncResourceVo> list = confExclusiveIndicatorMapper.queryBusinessSyncResource(params, page);

		if (page == null) {
			return R.ok(new PageDataInfo(list.size(), list));
		}

		return R.ok(new PageDataInfo(page, list));
	}

	/**
	 * 查询类型为父资源的可同步或已同步的业务服务资源列表
	 * @param params 专属指标同步请求参数
	 * @return 通用分页对象
	 */
	private R<PageDataInfo> queryParentSyncResource(IndicatorsSyncParams params) {

		Page<IndicatorSyncResourceVo> page = null;
		if (params.getPageNum() > 0 && params.getPageSize() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}

		List<IndicatorSyncResourceVo> list = confExclusiveIndicatorMapper.queryParentSyncResource(params, page);

		if (page == null) {
			return R.ok(new PageDataInfo(list.size(), list));
		}

		return R.ok(new PageDataInfo(page, list));
	}


	/**
	 * 专属指标同步
	 * @param params 专属指标同步请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R sync(IndicatorsSyncParams params) {
		// 1、校验服务资源是否存在
		QueryWrapper<ConfResource> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("resource_code", params.getResourceCoding());
		ConfResource br = confResourceService.getOne(queryWrapper);
		if (br == null) {
			return R.failed("该条数据不存在，请重新刷新页面！");
		}

		// 2、先删除要同步的
		List<String> syncResourceCodeList = params.getSyncResourceCodeList();
		confExclusiveIndicatorMapper.deleteByIdListAndResourceCode(params.getIds(), syncResourceCodeList);

		// 3、通过ids查询专属指标
		Date currentDate = new Date();
		List<ConfExclusiveIndicator> tempList = new ArrayList<>();
		List<ConfExclusiveIndicator> eiList = listByIds(params.getIds());
		for (ConfExclusiveIndicator ei : eiList) {
			for (String syncResourceCode : syncResourceCodeList) {
				ConfExclusiveIndicator dbEi = BeanUtils.convert(ei, ConfExclusiveIndicator.class);
				dbEi.setId(null);
				// 设置服务资源编码
				dbEi.setResourceCode(syncResourceCode);
				// 设置同步时间
				dbEi.setSynTime(YDateUtil.toLocalDateTime(currentDate));
				// 设置专属指标编码
				dbEi.setEiCode(ei.getEiCode());
				// 创建人
				dbEi.setCreateBy(SecurityUtils.getUser().getName());
				// 创建时间
				dbEi.setCreateTime(YDateUtil.toLocalDateTime(currentDate));
				tempList.add(dbEi);
			}
		}
		// 4、批量新增专属指标
		boolean flag = saveBatch(tempList, 5000);
		if (!flag) {
			return R.failed("新增专属指标失败");
		}
		return R.ok();
	}

	/**
	 * 专属指标同步移除
	 * @param params 专属指标同步请求参数
	 * @return 通用返回对象
	 */
	@Override
	public R unSync(IndicatorsSyncParams params) {
		int rows = confExclusiveIndicatorMapper.deleteByIdListAndResourceCode(
				params.getIds(), params.getUnSyncResourceCodeList());
		if (rows > 0) {
			return R.ok();
		}
		return R.failed("移除失败");
	}


	/**
	 * 专属指标同步所有
	 * @param params 专属指标同步请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R syncAll(IndicatorsSyncParams params) {
		// 1、查询可同步的服务资源列表
		List<IndicatorSyncResourceVo> list = BeanUtils.cast(querySureOrAlreadySyncResource(params).getData().getData());
		// 2、设置可同步的服务资源编码集合
		params.setSyncResourceCodeList(list
				.stream().map(IndicatorSyncResourceVo::getResourceCoding).collect(Collectors.toList()));
		// 3、专属指标同步
		return sync(params);
	}

	/**
	 * 专属指标同步移除所有
	 * @param params 专属指标同步请求参数
	 * @return 通用返回对象
	 */
	@Override
	public R unSyncAll(IndicatorsSyncParams params) {
		// 1、查询可同步的服务资源列表
		List<IndicatorSyncResourceVo> list = BeanUtils.cast(querySureOrAlreadySyncResource(params).getData().getData());
		// 2、设置可同步的服务资源编码集合
		params.setUnSyncResourceCodeList(list
				.stream().map(IndicatorSyncResourceVo::getResourceCoding).collect(Collectors.toList()));
		// 3、专属指标同步移除
		return unSync(params);
	}


}
